﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using PHMEE.Admin.Application.Contracts;
using PHMEE.CommonUtils;
using PHMEE.Managers.Diagnosis;
using PHMEE.PHM.Algorithms.Basic;
using PHMEE.TDengineInfrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using TDengine.Data.Client;
using Volo.Abp;
using Volo.Abp.Guids;

namespace PHMEE.Admin
{
    public class MqttAppService : PHMEEAdminAppService, IMqttAppService
    {
        private readonly ILogger<MqttAppService> _logger;
        private readonly TrendFeaAlg _trendFeaAlg;
        private readonly ITDConnectionFactory _tdConnectionFactory;
        private readonly IConfiguration _configuration;
        private readonly ICollectParaAppService _collectParaAppService;
        private readonly IThresholdAppService _thresholdAppService;
        private readonly VibAlarmEventPublisher _vibAlarmEventPublisher;

        //数据库名称
        private string dbName;
        public MqttAppService(IConfiguration configuration, ITDConnectionFactory tdConnectionFactory, ILogger<MqttAppService> logger, TrendFeaAlg trendFeaAlg, ICollectParaAppService collectParaAppService, IThresholdAppService thresholdAppService, VibAlarmEventPublisher vibAlarmEventPublisher)
        {
            _configuration = configuration;
            _tdConnectionFactory = tdConnectionFactory;
            _logger = logger;
            _trendFeaAlg = trendFeaAlg;
            _collectParaAppService = collectParaAppService;
            _thresholdAppService = thresholdAppService;
            _vibAlarmEventPublisher = vibAlarmEventPublisher;
            dbName = _configuration.GetValue<string>("TDengine:dbName");
        }

        /// <summary>
        /// WaveData主题数据存储处理
        /// </summary>
        /// <param name="waveDataReqDto"></param>
        /// <returns></returns>
        public async Task InsertWaveData(string requestInfo, string sn)
        {
            await Task.Run(async () =>
            {
                float acc_rms_warning = 0f;//加速度有效值三级阈值
                float acc_rms_alarm = 0f;//加速度有效值四级阈值
                float acc_avg_peak_warning = 0f;//加速度峰值三级阈值
                float acc_avg_peak_alarm = 0f;//加速度峰值四级阈值
                float vel_rms_warning = 0f;//速度有效值三级阈值
                float vel_rms_alarm = 0f;//速度有效值四级阈值
                try
                {
                    WaveDataReqDto waveDataReqDto = JsonConvert.DeserializeObject<WaveDataReqDto>(requestInfo)!;
                    //通道号
                    int chno = waveDataReqDto.ChNo;
                    //获取测点id，通道id, 数采器对应的采样频率
                    ReturnParaDto returnPara = await _collectParaAppService.GetByPoint(sn, chno);
                    //获取阈值
                    var thresholds = await _thresholdAppService.GetAllThresholdsAsync(returnPara.pointId);
                    if (thresholds != null)
                    {
                        foreach (var threshold in thresholds)
                        {
                            switch (threshold.LimitPara)
                            {
                                case LimitParaEnum.EffectiveSpeed://速度有效值
                                    vel_rms_warning = threshold.ThirdThreshold;
                                    vel_rms_alarm = threshold.FourthThreshold;
                                    break;
                                case LimitParaEnum.PeakAcceleration://加速度峰值
                                    acc_avg_peak_warning = threshold.ThirdThreshold;
                                    acc_avg_peak_alarm = threshold.FourthThreshold;
                                    break;
                                case LimitParaEnum.EffectiveAcc://加速度有效值
                                    acc_rms_warning = threshold.ThirdThreshold;
                                    acc_rms_alarm = threshold.FourthThreshold;
                                    break;
                                default:
                                    break;
                            }
                        }
                    }
                    DateTime baseTime = DateTime.UtcNow;
                    baseTime = new DateTime(baseTime.Year, baseTime.Month, baseTime.Day, baseTime.Hour, baseTime.Minute, baseTime.Second, 0);
                    baseTime = baseTime.ToUtcKind();

                    //波形数据超级表名
                    var superTableName = "wavedata_normal";
                    //波形数据子表名
                    var subTableName = $"wdn_{returnPara.pointId:N}";
                    //特征值超级表名
                    var eigenvalueSuperTableName = "wavedata_normal_eigenvalue";
                    //特征值子表名
                    var eigenvalueSubTableName = $"wdne_{returnPara.pointId:N}";

                    //表示报警数据
                    if (waveDataReqDto.AlarmLevel.HasValue)
                    {
                        superTableName = "wavedata_alarm";
                        subTableName = $"wda_{returnPara.pointId:N}";
                        eigenvalueSuperTableName = "wavedata_alarm_eigenvalue";
                        eigenvalueSubTableName = $"wdae_{returnPara.pointId:N}";
                    }
                    //乘以系数之后，得到的Float数据集合
                    List<float> floatsList = new List<float>();
                    for (int i = 0; i < waveDataReqDto.Content.Length; i += 2)
                    {
                        // 使用大端序方式从字节数组中读取16位整数
                        short rawValue = BitConverter.ToInt16([waveDataReqDto.Content[i + 1], waveDataReqDto.Content[i]], 0);
                        floatsList.Add((rawValue * waveDataReqDto.Coef) / 9.8f);
                    }
                    List<byte> allBytes = new List<byte>();
                    // 将浮点数列表转换为字节数组
                    foreach (var floatVal in floatsList)
                    {
                        allBytes.AddRange(BitConverter.GetBytes(floatVal));
                    }
                    //计算特征值
                    var eigenvalue = (await _trendFeaAlg.TrendFeaAsync(floatsList.ToArray(), returnPara.HighFreq));
                    //加速度有效值
                    float acc_rms = eigenvalue.AccRms;
                    //加速度平均峰值
                    float acc_avg_peak = eigenvalue.AccAvgPeak;
                    //速度有效值
                    float vel_rms = eigenvalue.VelRms;
                    //加速度包络平均峰值
                    float acc_env_avg_peak = eigenvalue.AccEnvAvgPeak;
                    // 分割字节数组为块
                    int blockSize = 64000; // 分块大小
                    int totalLength = allBytes.Count;
                    //分组数量
                    int numberOfchunks = (int)Math.Ceiling(totalLength / (double)blockSize);
                    // 获取数据库连接
                    using TDengineConnection dbConnection = _tdConnectionFactory.GetConnection();
                    using var command = dbConnection.CreateCommand();
                    using var command_alarm = dbConnection.CreateCommand();
                    using var command_eigenvalue = dbConnection.CreateCommand();
                    using var command_alarm_eigenvalue = dbConnection.CreateCommand();

                    for (int i = 0; i < numberOfchunks; i++)
                    {
                        //计算当前块的起始字节位置和长度
                        int offset = i * blockSize;
                        int length = Math.Min(blockSize, totalLength - offset);
                        byte[] chunk = allBytes.Skip(offset).Take(length).ToArray();
                        DateTime ts = baseTime.AddMilliseconds(i * 100);
                        var sql = "";
                        if (superTableName == "wavedata_normal")
                        {
                            sql = $"INSERT INTO {dbName}.{subTableName} USING {dbName}.{superTableName} (id ,pointid,chno) TAGS ('{returnPara.pipeId}','{returnPara.pointId}','{chno}') VALUES (? ,?);";
                        }
                        else if (superTableName == "wavedata_alarm")
                        {
                            sql = $"INSERT INTO {dbName}.{subTableName} USING {dbName}.{superTableName} (id ,pointid,chno) TAGS ('{returnPara.pipeId}','{returnPara.pointId}','{chno}') VALUES (? ,?);";
                        }
                        command_alarm.CommandText = sql;
                        var parameters = command_alarm.Parameters;
                        parameters.Add(new TDengineParameter("@0", ts));
                        parameters.Add(new TDengineParameter("@1", chunk));
                        int rows = command_alarm.ExecuteNonQuery();
                        command_alarm.Parameters.Clear();
                    }
                    var eigervalueSql = "";
                    if (superTableName == "wavedata_normal")
                    {
                        eigervalueSql = $"INSERT INTO {dbName}.{eigenvalueSubTableName} USING {dbName}.{eigenvalueSuperTableName} (id ,pointid,chno) TAGS ('{returnPara.pipeId}','{returnPara.pointId}','{chno}') VALUES (? ,? ,? ,? ,? ,? ,? ,? ,? ,? ,?);";
                        command_eigenvalue.CommandText = eigervalueSql;
                        var parameters = command_eigenvalue.Parameters;
                        parameters.Add(new TDengineParameter("@0", baseTime));
                        parameters.Add(new TDengineParameter("@1", acc_rms));
                        parameters.Add(new TDengineParameter("@2", acc_avg_peak));
                        parameters.Add(new TDengineParameter("@3", vel_rms));
                        parameters.Add(new TDengineParameter("@4", acc_env_avg_peak));
                        parameters.Add(new TDengineParameter("@5", acc_rms_warning));
                        parameters.Add(new TDengineParameter("@6", acc_rms_alarm));
                        parameters.Add(new TDengineParameter("@7", acc_avg_peak_warning));
                        parameters.Add(new TDengineParameter("@8", acc_avg_peak_alarm));
                        parameters.Add(new TDengineParameter("@9", vel_rms_warning));
                        parameters.Add(new TDengineParameter("@10", vel_rms_alarm));

                        int rows = command_eigenvalue.ExecuteNonQuery();
                        command_eigenvalue.Parameters.Clear();
                    }
                    else if (superTableName == "wavedata_alarm")
                    {
                        eigervalueSql = $"INSERT INTO {dbName}.{eigenvalueSubTableName} USING {dbName}.{eigenvalueSuperTableName} (id ,pointid,chno) TAGS ('{returnPara.pipeId}','{returnPara.pointId}','{chno}') VALUES (? ,? ,? ,? ,? ,? ,? ,? ,? ,? ,? ,?);";
                        command_alarm_eigenvalue.CommandText = eigervalueSql;
                        var parameters = command_alarm_eigenvalue.Parameters;
                        parameters.Add(new TDengineParameter("@0", baseTime));
                        parameters.Add(new TDengineParameter("@1", acc_rms));
                        parameters.Add(new TDengineParameter("@2", acc_rms_warning));
                        parameters.Add(new TDengineParameter("@3", acc_rms_alarm));
                        parameters.Add(new TDengineParameter("@4", acc_avg_peak));
                        parameters.Add(new TDengineParameter("@5", acc_avg_peak_warning));
                        parameters.Add(new TDengineParameter("@6", acc_avg_peak_alarm));
                        parameters.Add(new TDengineParameter("@7", vel_rms));
                        parameters.Add(new TDengineParameter("@8", vel_rms_warning));
                        parameters.Add(new TDengineParameter("@9", vel_rms_alarm));
                        parameters.Add(new TDengineParameter("@10", acc_env_avg_peak));
                        parameters.Add(new TDengineParameter("@11", waveDataReqDto.AlarmLevel));
                        int rows = command_alarm_eigenvalue.ExecuteNonQuery();
                        command_alarm_eigenvalue.Parameters.Clear();

                        await _vibAlarmEventPublisher.PublishAsync(returnPara.pointId, baseTime);
                    }
                    Console.WriteLine($"插入采集站【{sn}】,通道【{chno}】成功");
                    #region 查询测试
                    //// 查询测试
                    //command.CommandText = $"SELECT * FROM {dbName}.test_1 Order BY ts desc  LIMIT 1;";
                    //using var reader = command.ExecuteReader();
                    //while (reader.Read())
                    //{
                    //    var thisTs = ((DateTime)reader.GetValue(0)).ToString("yyyy-MM-dd HH:mm:ss.fff");
                    //    Console.WriteLine("ts:" + ts);

                    //    var rawValuesBytes = (byte[])reader.GetValue(1);

                    //    List<float> doublesList = new List<float>();
                    //    for (int i = 0; i < rawValuesBytes.Length; i += 2)
                    //    {
                    //        //float value = BitConverter.ToSingle(rawValuesBytes, i);
                    //        //doublesList.Add(value);

                    //        // 由于是大端序，需要首先交换字节
                    //        byte temp = rawValuesBytes[i];
                    //        rawValuesBytes[i] = rawValuesBytes[i + 1];
                    //        rawValuesBytes[i + 1] = temp;

                    //        // 现在转换为16位整数
                    //        short rawValue = BitConverter.ToInt16(rawValuesBytes, i);

                    //        // 将整数转换为浮点数，并应用系数
                    //        float value = rawValue * waveDataReqDto.Coef;
                    //        doublesList.Add(value);
                    //    }

                    //    Console.WriteLine("rawValues:" + string.Join(",", doublesList));

                    //    //var featureValue1 = reader.GetValue(2);
                    //    //Console.WriteLine("featureValue1:" + featureValue1);
                    //    //var featureValue2 = reader.GetValue(3);
                    //    //Console.WriteLine("featureValue2:" + featureValue2);
                    //}
                    #endregion

                    string fileName = $@"WaveData_Content_{DateTime.Now.ToString("yyyy-MM-ddTHH-mm-ss")}.txt";
                    //WriteFileHelper.WriteFile("81001001", fileName, floatContent);
                }
                catch (UserFriendlyException ex)
                {
                    _logger.LogError(ex, "插入数据时出现错误:{Message}", ex.Message);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "插入数据发生未知错误:{Message}", ex.Message);
                }

            });
        }
        /// <summary>
        /// 零均值化处理
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static List<float> ZeroMean(List<float> data)
        {
            float mean = data.Average();  // 计算均值
            var dataRes = data.Select(x => x - mean).ToList();  // 零均值处理
            return dataRes;
        }
    }
}
